package com.sanyuan.cloud.module.system.service.nongmo.impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.date.DatePattern;
import cn.hutool.core.util.StrUtil;
import com.sanyuan.cloud.framework.common.pojo.PageResult;
import com.sanyuan.cloud.framework.common.util.collection.CollectionUtils;
import com.sanyuan.cloud.framework.common.util.id.SnowflakeIdUtil;
import com.sanyuan.cloud.framework.common.util.object.BeanUtils;
import com.sanyuan.cloud.module.system.controller.admin.nongmo.req.PositionAssignReq;
import com.sanyuan.cloud.module.system.controller.app.position.req.CheckRecordReqVO;
import com.sanyuan.cloud.module.system.controller.app.position.req.OverViewStatisticsReqVO;
import com.sanyuan.cloud.module.system.controller.app.position.req.PositionReqVO;
import com.sanyuan.cloud.module.system.controller.app.position.req.VisitReqVO;
import com.sanyuan.cloud.module.system.controller.app.position.vo.*;
import com.sanyuan.cloud.module.system.dal.dataobject.nongmo.SystemPositionCheckRecordDO;
import com.sanyuan.cloud.module.system.dal.dataobject.nongmo.SystemPositionDO;
import com.sanyuan.cloud.module.system.dal.dataobject.nongmo.SystemPositionUserDO;
import com.sanyuan.cloud.module.system.dal.dataobject.user.AdminUserDO;
import com.sanyuan.cloud.module.system.dal.mysql.nongmo.SystemPositionCheckRecordMapper;
import com.sanyuan.cloud.module.system.dal.mysql.nongmo.SystemPositionMapper;
import com.sanyuan.cloud.module.system.dal.mysql.nongmo.SystemPositionUserMapper;
import com.sanyuan.cloud.module.system.dal.mysql.user.AdminUserMapper;
import com.sanyuan.cloud.module.system.enums.nongmo.CommonEnums;
import com.sanyuan.cloud.module.system.service.nongmo.AppPositionService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.cloud.context.config.annotation.RefreshScope;
import org.springframework.data.geo.*;
import org.springframework.data.redis.connection.RedisGeoCommands;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.LocalTime;
import java.time.format.DateTimeFormatter;
import java.util.*;
import java.util.stream.Collectors;

import static com.sanyuan.cloud.framework.common.exception.util.ServiceExceptionUtil.exception;
import static com.sanyuan.cloud.framework.security.core.util.SecurityFrameworkUtils.getLoginUserId;
import static com.sanyuan.cloud.module.infra.enums.ErrorCodeConstants.NONGMO_DATA_NOT_EXISTS;
import static com.sanyuan.cloud.module.system.enums.ErrorCodeConstants.*;
import static com.sanyuan.cloud.module.system.enums.nongmo.AuthEnums.AUTY_TYPE_ADMIN;
import static com.sanyuan.cloud.module.system.enums.nongmo.AuthEnums.AUTY_TYPE_MEMEBER;
import static com.sanyuan.cloud.module.system.enums.nongmo.CommonEnums.VISIT_STATUS_0;
import static com.sanyuan.cloud.module.system.enums.nongmo.NongmoRedisKeyConstants.CHECK_IN_LOCATION_KEY;
import static com.sanyuan.cloud.module.system.enums.nongmo.NongmoRedisKeyConstants.GEO_KEY;

/**
 * @Description: AppPositionServiceImpl
 * @Author: wuyuwei
 * @Date: 2025/3/28
 */
@Slf4j
@Service
@RefreshScope
public class AppPositionServiceImpl implements AppPositionService {
    SnowflakeIdUtil snowflakeIdUtil = new SnowflakeIdUtil();
    @Value("${nongmo.check.radiusKmValue:1.0}")
    private Double radiusKmValue;
    @Value("${nongmo.check.defaultRadiusKm:5.0}")
    private Double defaultRadiusKm;

    @Resource
    private SystemPositionMapper systemPositionMapper;
    @Resource
    private SystemPositionUserMapper systemPositionUserMapper;
    @Resource
    private AdminUserMapper adminUserMapper;
    @Resource
    private RedisTemplate<String, Object> redisTemplate;
    @Resource
    private SystemPositionCheckRecordMapper systemPositionCheckRecordMapper;

    @Transactional(rollbackFor = Exception.class)
    @Override
    public Boolean addPosition(PositionReqVO reqVO) {
        log.info("--- addPosition reqVO:{}",reqVO);
        SystemPositionDO systemPositionDO = systemPositionMapper.selectEntityOne(reqVO);
        if (Objects.nonNull(systemPositionDO)){
            throw exception(NONGMO_WEIXIN_MINI_POSITION_EXISTS);
        }
        String loginUserId = String.valueOf(getLoginUserId());
        AdminUserDO userInfo = adminUserMapper.selectById(loginUserId);
        if (null == userInfo){
            throw exception(NONGMO_USER_NOT_EXISTS);
        }
        systemPositionDO = new SystemPositionDO();
        BeanUtils.copyProperties(reqVO, systemPositionDO);
        systemPositionDO.setCreator(loginUserId);
        systemPositionDO.setUpdater(loginUserId);
        systemPositionMapper.insertEntity(systemPositionDO);
        Long id = systemPositionDO.getId();

        SystemPositionUserDO systemPositionUserDO = new SystemPositionUserDO();
        systemPositionUserDO.setPositionId(id);
        if (userInfo.getIsAdmin().equals(AUTY_TYPE_ADMIN.getCode())){
            // 当前登录用户是管理员
            systemPositionUserDO.setUserId(reqVO.getUserId());
            if (null!=reqVO.getUserId()){
                AdminUserDO adminUserDO = adminUserMapper.selectById(reqVO.getUserId());
                systemPositionUserDO.setUsername(adminUserDO.getUsername());
            }
        }else if (userInfo.getIsAdmin().equals(AUTY_TYPE_MEMEBER.getCode())){
            systemPositionUserDO.setUserId(getLoginUserId());
            systemPositionUserDO.setUsername(userInfo.getUsername());
        }
        systemPositionUserDO.setStatus(Integer.parseInt(VISIT_STATUS_0.getCode()));
        systemPositionUserMapper.insert(systemPositionUserDO);
        return true;
    }

    @Override
    public List<SystemPositionV0> findNearbyPositions(double longitude, double latitude, Double radiusKm) {
        log.info("--- findNearbyPositions longitude:{},latitude:{},radiusKm:{}",longitude,latitude,radiusKm);
        // 1. 查询Redis获取附近的位置ID
        Circle within = new Circle(new Point(longitude, latitude), new Distance(null!=radiusKm?radiusKm:defaultRadiusKm, Metrics.KILOMETERS));
        GeoResults<RedisGeoCommands.GeoLocation<Object>> results = redisTemplate.opsForGeo()
                .radius(GEO_KEY, within);

        // 2. 提取ID并查询MySQL
        if (results == null) {
            return Collections.emptyList();
        }
        List<Long> ids = results.getContent().stream()
                .map(geoResult -> Long.parseLong(geoResult.getContent().getName().toString()))
                .collect(Collectors.toList());

        if (CollUtil.isEmpty(ids)){
            return Collections.emptyList();
        }

        List<SystemPositionDO> collect = systemPositionMapper.selectBatchIds(ids).stream()
                .filter(pos -> !pos.getDeleted())
                .collect(Collectors.toList());
        if (CollUtil.isEmpty(collect)){
            return Collections.emptyList();
        }

        List<SystemPositionUserDO> systemPositionUserDOS = systemPositionUserMapper.selectPositionUserByPositionIds(collect.stream()
                .map(SystemPositionDO::getId).collect(Collectors.toList()));
        if (CollUtil.isNotEmpty(systemPositionUserDOS)){
            // value是操作记录集合根据更新时间倒序取最近一个操作记录
            Map<Long, SystemPositionUserDO> map = systemPositionUserDOS.stream().collect(Collectors.groupingBy(SystemPositionUserDO::getPositionId,
                    Collectors.collectingAndThen(Collectors.toList(), value -> getLatestRecord(value))));
            collect.forEach(data->{
                if (map.containsKey(data.getId())){
                    SystemPositionUserDO systemPositionUserDO = map.get(data.getId());
                    data.setVisitStatus(systemPositionUserDO.getStatus());
                }
            });
        }
        // 查询管理用户信息
        List<SystemPositionUserDO> positionUserDOList = systemPositionUserMapper.selectPositionUserByPositionIds(ids);
        Map<Long, List<SystemPositionUserDO>> map = new HashMap<>();
        if (CollUtil.isNotEmpty(positionUserDOList)){
            map = positionUserDOList.stream()
                    .collect(Collectors.groupingBy(SystemPositionUserDO::getPositionId, Collectors.toList()));
        }
        Map<Long, List<SystemPositionUserDO>> finalMap = map;
        List<SystemPositionV0> convertList = CollectionUtils.convertList(collect, data -> {
            SystemPositionV0 systemPositionV0 = new SystemPositionV0();
            BeanUtil.copyProperties(data, systemPositionV0);
            if (finalMap.containsKey(data.getId())) {
                List<SystemPositionUserDO> list = finalMap.get(data.getId());
                if (CollUtil.isNotEmpty(list)) {
                    SystemPositionUserDO systemPositionUserDO = list.get(0);
                    systemPositionV0.setUserId(systemPositionUserDO.getUserId());
                    systemPositionV0.setUsername(systemPositionUserDO.getUsername());
                }
            }
            systemPositionV0.setLatitude(trimTrailingZeros(data.getLatitude()));
            systemPositionV0.setLongitude(trimTrailingZeros(data.getLongitude()));
            return systemPositionV0;
        });
        Long loginUserId = getLoginUserId();
        AdminUserDO adminUserDO = adminUserMapper.selectById(loginUserId);
        if (null!=adminUserDO && AUTY_TYPE_ADMIN.getCode().equals(adminUserDO.getIsAdmin())){
            return convertList;
        }
        List<SystemPositionV0> resultList = convertList.stream().filter(data -> null!=data.getUserId() && data.getUserId().equals(loginUserId)).collect(Collectors.toList());
        return resultList;
    }

    /**
     * 截取数值字符串末尾的冗余零（若存在）
     * @param number 输入字符串（如 "114.03165000000000"）
     * @return 去除末尾零的字符串（如 "114.03165"）
     */
    public static String trimTrailingZeros(String number) {
        if (number == null || number.isEmpty()) {
            return number;
        }

        // 处理步骤：
        // 1. 去除末尾连续的零
        // 2. 如果小数点后没有有效数字，去除小数点
        String trimmed = number.replaceAll("0+$", "");
        trimmed = trimmed.replaceAll("\\.$", "");
        return trimmed;
    }

    /**
     * 根据创建时间倒序
     * @param operateRecordDTOList
     * @return
     */
    private SystemPositionUserDO getLatestRecord(List<SystemPositionUserDO> operateRecordDTOList) {
        if (CollUtil.isEmpty(operateRecordDTOList)){
            return new SystemPositionUserDO();
        }
        List<SystemPositionUserDO> collect = operateRecordDTOList.stream()
                .sorted(Comparator.comparing(SystemPositionUserDO::getUpdateTime).reversed())
                .collect(Collectors.toList());
        return collect.get(0);
    }

    @Override
    public void assign(PositionAssignReq req) {
        log.info("--- assign req:{}",req);
        SystemPositionDO systemPositionDO = systemPositionMapper.selectById(req.getId());
        if (null == systemPositionDO){
            throw exception(NONGMO_DATA_NOT_EXISTS);
        }
        AdminUserDO adminUserDO = adminUserMapper.selectById(req.getUserId());
        SystemPositionUserDO systemPositionUserDO = systemPositionUserMapper.selectPositionUserByPositionId(systemPositionDO.getId());
        if (null != systemPositionUserDO){
            systemPositionUserMapper.deleteById(systemPositionUserDO.getId());
        }
        SystemPositionUserDO entity = new SystemPositionUserDO();
        entity.setPositionId(req.getId());
        entity.setUserId(req.getUserId());
        if (null != adminUserDO){
            entity.setUsername(adminUserDO.getUsername());
        }
        entity.setStatus(Integer.parseInt(VISIT_STATUS_0.getCode()));
        systemPositionUserMapper.insert(entity);
    }

    @Transactional(rollbackFor = Exception.class)
    @Override
    public Boolean delete(String id) {
        log.info("--- delete id:{}",id);
        systemPositionMapper.deleteById(id);
        systemPositionUserMapper.deleteByPositionId(Long.valueOf(id));
        return true;
    }

    @Override
    public PositionVO detail(String id) {
        log.info("--- detail id:{}",id);
        SystemPositionDO systemPositionDO = systemPositionMapper.selectById(id);
        if (Objects.isNull(systemPositionDO)){
            throw exception(NONGMO_WEIXIN_MINI_POSITION_NOT_EXISTS);
        }
        SystemPositionUserDO systemPositionUserDOS = systemPositionUserMapper.selectPositionUserByPositionId(id);
        PositionVO positionVO = BeanUtils.toBean(systemPositionDO, PositionVO.class);
        if (null != systemPositionUserDOS){
            positionVO.setUserId(systemPositionUserDOS.getUserId());
            positionVO.setUsername(systemPositionUserDOS.getUsername());
            positionVO.setVisitStatus(systemPositionUserDOS.getStatus());
            positionVO.setRemark(systemPositionUserDOS.getRemark());
        }
        return positionVO;
    }

    @Override
    public UserVisitInfoVO getVisitInfoByUserAndTimeSlot(VisitReqVO reqVO) {
        log.info("--- getVisitInfoByUserAndTimeSlot reqVO:{}",reqVO);
        // 1. 使用LocalDateTime处理日期时间（线程安全且更规范）
        // 当天00:00:00
        LocalDateTime beginDateTime = reqVO.getStartDate().atStartOfDay();
        // 当天23:59:59.999999999
        LocalDateTime endDateTime = reqVO.getEndDate().atTime(LocalTime.MAX);

        // 2. 更新请求参数（如果需要保持String类型）
        List<SystemPositionUserDO> entities = systemPositionUserMapper.selectUserAndTimeSlot(reqVO, beginDateTime, endDateTime);
        List<SystemPositionUserDO> totalEntities = systemPositionUserMapper.selectUserAndTimeSlot(reqVO, null, null);
        UserVisitInfoVO userVisitInfoVO = new UserVisitInfoVO();
        if (CollUtil.isEmpty(entities)){
            return userVisitInfoVO;
        }
        userVisitInfoVO.setUsername(entities.get(0).getUsername());
        DateTimeFormatter df = DateTimeFormatter.ofPattern(DatePattern.NORM_DATE_PATTERN);
        userVisitInfoVO.setBeginDate(df.format(beginDateTime));
        userVisitInfoVO.setEndDate(df.format(endDateTime));
        userVisitInfoVO.setNewPositionNum(entities.size());
        List<SystemPositionUserDO> visitedList = entities.stream()
                .filter(data -> !VISIT_STATUS_0.getCode().equals(String.valueOf(data.getStatus())))
                .collect(Collectors.toList());
        userVisitInfoVO.setVisitNum(visitedList.size());
        List<SystemPositionUserDO> visitedSuccessList = entities.stream()
                .filter(data -> CommonEnums.VISIT_STATUS_3.getCode().equals(String.valueOf(data.getStatus())))
                .collect(Collectors.toList());
        userVisitInfoVO.setVisitSuccessedNum(visitedSuccessList.size());
        List<SystemPositionUserDO> visitedFllowupList = entities.stream()
                .filter(data -> CommonEnums.VISIT_STATUS_2.getCode().equals(String.valueOf(data.getStatus())))
                .collect(Collectors.toList());
        userVisitInfoVO.setVisitFllowupNum(visitedFllowupList.size());
        userVisitInfoVO.setTotalPoints(totalEntities.size());
        return userVisitInfoVO;
    }

    @Override
    public List<DistrictVisitInfoVO> getDistrictVisitInfo(PositionReqVO reqVO) {
        log.info("--- getDistrictVisitInfo reqVO:{}",reqVO);
        Long loginUserId = getLoginUserId();
        AdminUserDO adminUserDO = adminUserMapper.selectById(loginUserId);
        if (null == adminUserDO){
            throw exception(NONGMO_USER_NOT_EXISTS);
        }
        Double longitude = reqVO.getLongitude();
        Double latitude = reqVO.getLatitude();
        double radiusKm = null!=reqVO.getRadiusKm()?reqVO.getRadiusKm():defaultRadiusKm;
        // 1. 查询Redis获取附近的位置ID
        Circle within = new Circle(new Point(longitude, latitude), new Distance(radiusKm, Metrics.KILOMETERS));
        GeoResults<RedisGeoCommands.GeoLocation<Object>> results = redisTemplate.opsForGeo()
                .radius(GEO_KEY, within);

        // 2. 提取ID并查询MySQL
        if (results == null) {
            return Collections.emptyList();
        }
        List<Long> ids = results.getContent().stream()
                .map(geoResult -> Long.parseLong(geoResult.getContent().getName().toString()))
                .collect(Collectors.toList());
        if (CollUtil.isEmpty(ids)){
            return Collections.emptyList();
        }

        List<SystemPositionDO> systemPositionDOS = systemPositionMapper.selectBatchIds(ids);
        Map<Long, String> positionMap = systemPositionDOS.stream().collect(Collectors.toMap(SystemPositionDO::getId, data->data.getName()));

        // 查询用户关联的标点信息
        LocalDateTime beginDateTime = null;
        if (null!=reqVO.getStartDate()){
            // 当天00:00:00
            beginDateTime = reqVO.getStartDate().atStartOfDay();
        }
        LocalDateTime endDateTime= null;
        if (null!=reqVO.getEndDate()){
            // 当天23:59:59.999999999
            endDateTime = reqVO.getEndDate().atTime(LocalTime.MAX);
        }

        List<SystemPositionUserDO> systemPositionUserDOS = systemPositionUserMapper.selectByPositionIdAndUserId(ids, reqVO.getUserId(),beginDateTime,endDateTime).stream()
                .filter(record -> !record.getDeleted())
                .collect(Collectors.toList());

        List<DistrictVisitInfoVO> convertList = CollectionUtils.convertList(systemPositionUserDOS, record -> {
            DistrictVisitInfoVO districtVisitInfoVO = new DistrictVisitInfoVO();
            districtVisitInfoVO.setId(record.getPositionId());
            if (positionMap.containsKey(record.getPositionId())) {
                districtVisitInfoVO.setPositionName(positionMap.get(record.getPositionId()));
            }
            districtVisitInfoVO.setUserId(record.getUserId());
            districtVisitInfoVO.setUsername(record.getUsername());
            districtVisitInfoVO.setVisitStatus(record.getStatus());
            SystemPositionDO systemPositionDO = systemPositionMapper.selectById(record.getPositionId());
            if (null!=systemPositionDO){
                districtVisitInfoVO.setLongitude(systemPositionDO.getLongitude());
                districtVisitInfoVO.setLatitude(systemPositionDO.getLatitude());
            }

            return districtVisitInfoVO;
        });
        if (null!=adminUserDO && AUTY_TYPE_ADMIN.getCode().equals(adminUserDO.getIsAdmin())){
            return convertList;
        }
        convertList = convertList.stream()
                .filter(data -> data.getUserId() == getLoginUserId())
                .collect(Collectors.toList());

        return convertList;
    }

    @Transactional(rollbackFor = Exception.class)
    @Override
    public Boolean initCheckInLocation(PositionReqVO reqVO) {
        log.info("--- initCheckInLocation reqVO:{}",reqVO);
        SystemPositionCheckRecordDO checkRecordDO = systemPositionCheckRecordMapper.selectByPositionIdAndUserId(Long.valueOf(reqVO.getId()),
                getLoginUserId(),CommonEnums.BUSINESS_STATUS_0.getCode());
        if (Objects.nonNull(checkRecordDO)){
            // 如果已存在，则更新时间   兼容用户多次点击出发申请情况，取最新一次
            checkRecordDO.setUpdateTime(LocalDateTime.now());
            checkRecordDO.setUpdater(String.valueOf(getLoginUserId()));
            systemPositionCheckRecordMapper.updateById(checkRecordDO);
        }else {
            // 记录出发信息
            SystemPositionCheckRecordDO positionCheckRecordDO = new SystemPositionCheckRecordDO();
            SystemPositionDO systemPositionDO = systemPositionMapper.selectById(reqVO.getId());
            if (null == systemPositionDO){
                throw exception(NONGMO_DATA_NOT_EXISTS);
            }
            positionCheckRecordDO.setPositionName(systemPositionDO.getName());
            positionCheckRecordDO.setPositionId(Long.valueOf(reqVO.getId()));
            positionCheckRecordDO.setUserId(getLoginUserId());
            long nextId = snowflakeIdUtil.nextId();
            positionCheckRecordDO.setBusinessId(nextId);
            positionCheckRecordDO.setStatus(Integer.parseInt(CommonEnums.BUSINESS_STATUS_0.getCode()));
            AdminUserDO loginUser = adminUserMapper.selectById(getLoginUserId());
            if (null!=loginUser){
                String username = loginUser.getUsername();
                positionCheckRecordDO.setUsername(username);
            }
            systemPositionCheckRecordMapper.insert(positionCheckRecordDO);
        }
        return true;
    }

    @Transactional(rollbackFor = Exception.class)
    @Override
    public Boolean checkIn(PositionReqVO reqVO) {
        log.info("--- checkIn reqVO:{}",reqVO);
        if (StrUtil.isBlank(reqVO.getId())){
            throw exception(NONGMO_WEIXIN_MINI_POSITION_ID_IS_NULL);
        }
        // 查询打卡目标标点信息
        SystemPositionDO systemPositionDO = systemPositionMapper.selectById(reqVO.getId());
        if (null == systemPositionDO){
            throw exception(NONGMO_WEIXIN_MINI_POSITION_NOT_EXISTS);
        }
        // 将打卡目标标点信息坐标位置放入缓存GEO
        double longitude = Double.valueOf(systemPositionDO.getLongitude());
        double latitude = Double.valueOf(systemPositionDO.getLatitude());
        Point point = new Point(longitude, latitude);
        redisTemplate.opsForGeo().add(CHECK_IN_LOCATION_KEY, point, getLoginUserId());

        // 根据用户当前经纬度，计算与目标标点位置距离。在要求的范围内则打卡成功，否则打卡失败
        Long loginUserId = getLoginUserId();
        // 当前经度
        double currentLng = reqVO.getLongitude();
        // 当前纬度
        double currentLat = reqVO.getLatitude();
        // 允许半径
        double radiusKm = null!=reqVO.getRadiusKm()?reqVO.getRadiusKm():radiusKmValue;
        // 构造查询范围参数
        Circle circle = new Circle(new Point(currentLng, currentLat),
                new Distance(radiusKm, Metrics.KILOMETERS));

        RedisGeoCommands.GeoRadiusCommandArgs args = RedisGeoCommands.GeoRadiusCommandArgs.newGeoRadiusArgs()
                .includeDistance()     // 返回结果包含距离信息
                .includeCoordinates()  // 返回结果包含坐标信息
                .sortAscending();      // 按距离升序排列（从近到远）

        // 查询半径内的所有成员  查询Redis中存储在CHECK_IN_LOCATION_KEY下的所有位置，找到位于circle范围内的记录
        GeoResults<RedisGeoCommands.GeoLocation<Object>> results = redisTemplate.opsForGeo()
                .radius(CHECK_IN_LOCATION_KEY, circle, args);

        // 如果范围内的标点包好打卡目标标点，则打卡成功
        if (results != null) {
            for (GeoResult<RedisGeoCommands.GeoLocation<Object>> result : results) {
                if (String.valueOf(result.getContent().getName()).equals(String.valueOf(loginUserId))) {
                    // 记录打卡信息
                    SystemPositionCheckRecordDO checkedRecordDO = systemPositionCheckRecordMapper.selectByPositionIdAndUserId(Long.valueOf(reqVO.getId()), getLoginUserId(),CommonEnums.BUSINESS_STATUS_1.getCode());
                    if (Objects.nonNull(checkedRecordDO)){
                        // 已打卡，则仅更新时间
                        checkedRecordDO.setUpdateTime(LocalDateTime.now());
                        checkedRecordDO.setUpdater(String.valueOf(getLoginUserId()));
                        systemPositionCheckRecordMapper.updateById(checkedRecordDO);
                    }else {
                        SystemPositionCheckRecordDO checkRecordDO = systemPositionCheckRecordMapper.selectByPositionIdAndUserId(Long.valueOf(reqVO.getId()), loginUserId,CommonEnums.BUSINESS_STATUS_0.getCode());
                        log.info("---- checkIn checkRecordDO:{}",checkRecordDO);
                        SystemPositionCheckRecordDO positionCheckRecordDO = new SystemPositionCheckRecordDO();
                        if (null == checkRecordDO){
                            log.error("--- checkIn 用户{}没有进行出发申请",  loginUserId);
                            positionCheckRecordDO.setRemark("当前用户没有进行出发申请");
                        }else {
                            positionCheckRecordDO.setBusinessId(checkRecordDO.getBusinessId());
                        }
                        positionCheckRecordDO.setPositionId(Long.valueOf(reqVO.getId()));
                        positionCheckRecordDO.setUserId(getLoginUserId());
                        positionCheckRecordDO.setStatus(Integer.parseInt(CommonEnums.BUSINESS_STATUS_1.getCode()));
                        AdminUserDO loginUser = adminUserMapper.selectById(getLoginUserId());
                        if (null!=loginUser){
                            String username = loginUser.getUsername();
                            positionCheckRecordDO.setUsername(username);
                        }
                        positionCheckRecordDO.setPositionName(systemPositionDO.getName());
                        systemPositionCheckRecordMapper.insert(positionCheckRecordDO);
                    }
                    return true;
                }
            }
        }
        return false;
    }

    @Override
    public Boolean updateVisitStatus(VisitReqVO reqVO) {
        log.info("--- updateVisitStatus reqVO:{}",reqVO);
        SystemPositionDO systemPositionDO = systemPositionMapper.selectById(reqVO.getId());
        if (Objects.isNull(systemPositionDO)){
            throw exception(NONGMO_WEIXIN_MINI_POSITION_NOT_EXISTS);
        }
        SystemPositionUserDO systemPositionUserDO = systemPositionUserMapper.selectPositionUserByPositionId(systemPositionDO.getId(), getLoginUserId());
        if (null == systemPositionUserDO){
            throw exception(NONGMO_WEIXIN_MINI_POSITION_NOT_BELONG);
        }
        systemPositionUserDO.setStatus(reqVO.getStatus());
        systemPositionUserDO.setRemark(reqVO.getRemark());
        systemPositionUserDO.setUpdateTime(LocalDateTime.now());
        systemPositionUserMapper.updateById(systemPositionUserDO);
        return true;
    }

    @Override
    public OverViewStatisticsRespVO overViewStatistics(OverViewStatisticsReqVO reqVO) {
        log.info("--- overViewStatistics reqVO:{}",reqVO);
        // 总标点数量
        Long positionCount = systemPositionMapper.countPosition();
        // 总业务员数量
        Long userCount = adminUserMapper.countUser();
        // 今日打卡数量
        if (StrUtil.isBlank(reqVO.getStartDate())){
            reqVO.setStartDate(LocalDate.now().format(DateTimeFormatter.ofPattern("yyyy-MM-dd")));
        }
        if (StrUtil.isBlank(reqVO.getEndDate())){
            reqVO.setEndDate(LocalDate.now().format(DateTimeFormatter.ofPattern("yyyy-MM-dd")));
        }
        Long visitCount = systemPositionCheckRecordMapper.selectCountBetweenTime(reqVO.getStartDate(), reqVO.getEndDate());
        return new OverViewStatisticsRespVO(positionCount,visitCount,userCount);
    }

    @Override
    public PageResult<CheckRecordRespVO> getCheckRecord(CheckRecordReqVO reqVO) {
        if (reqVO.getPageNo()>0){
            reqVO.setPageNo(reqVO.getPageNo()-1);
        }
        long total = systemPositionCheckRecordMapper.selectByCount(reqVO);
        if (total<=0L){
            return PageResult.empty();
        }
        List<CheckRecordRespVO> list = systemPositionCheckRecordMapper.selectListBetweenTime(reqVO);
        return new PageResult<>(list,total);
    }

    @Override
    public PositionVO getLatestRecord(VisitReqVO reqVO) {
        // 当天00:00:00
        LocalDateTime beginDateTime = reqVO.getStartDate().atStartOfDay();
        // 当天23:59:59.999999999
        LocalDateTime endDateTime = reqVO.getEndDate().atTime(LocalTime.MAX);

        // 2. 更新请求参数（如果需要保持String类型）
        SystemPositionUserDO entity = systemPositionUserMapper.selectOneUserAndTimeSlot(reqVO, beginDateTime, endDateTime);
        if (null == entity){
            return null;
        }
        SystemPositionDO systemPositionDO = systemPositionMapper.selectById(entity.getPositionId());
        if (null == systemPositionDO){
          return null;
        }
        PositionVO positionVO = new PositionVO();
        BeanUtil.copyProperties(systemPositionDO,positionVO);
        return positionVO;
    }
}
